package com.baofu.paycore.service.processor.withdraw;

import com.baofu.clear.service.facade.enums.EventTypeEnum;
import com.baofu.paycore.biz.external.clear.EventService;
import com.baofu.paycore.biz.external.clear.model.EventRuleResBO;
import com.baofu.paycore.common.enums.FundTypeEnum;
import com.baofu.paycore.common.exception.PayCoreBizException;
import com.baofu.paycore.common.utils.Constant;
import com.baofu.paycore.manager.model.FreezeBO;
import com.baofu.paycore.manager.model.withdraw.WithdrawBO;
import com.baofu.paycore.manager.model.withdraw.WithdrawFundBO;
import com.baofu.paycore.manager.storer.FreezeOrderRepository;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import com.baofu.paycore.service.facade.enums.PayToolTypeEnum;
import com.baofu.paycore.service.facade.enums.ServiceCodeEnum;
import com.baofu.paycore.service.facade.model.withdraw.UnfreezeWithdrawDTO;
import com.baofu.paycore.service.facade.model.withdraw.WithDrawFundDTO;
import com.system.commons.exception.BizServiceException;
import com.system.commons.sequence.redis.SequenceFacade;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 提现资金单处理类
 *
 * <p/>
 *      1、构建支付属性
 * </p>
 * User: LZQ Date: 2016/04/20  Version: 1.0
 */
@Slf4j
@Component
public class UnfreezeWithdrawFundProcessor{

    /**
     * 资金明细单号生成
     */
    @Autowired
    private SequenceFacade sequenceFacade;

    /**
     * 会计事件服务
     */
    @Autowired
    private EventService eventService;

    /**
     * 冻结服务
     */
    @Autowired
    private FreezeOrderRepository freezeOrderRepository;


    /**
     * 构建支付属性
     *
     * @param withdrawBO      支付模型
     * @param withdrawDTO     请求参数
     */
    public void process(WithdrawBO withdrawBO, UnfreezeWithdrawDTO withdrawDTO) {

        //提现资金单
        WithDrawFundDTO withDrawFundDTO = withdrawDTO.getWithDrawFundDTO();
        FreezeBO freezeBO = freezeOrderRepository.load(withdrawDTO.getOrigPayNo());
        if (freezeBO == null) {
            log.error("对应的冻结订单不存在,冻结单号:{}", withdrawDTO.getOrigPayNo());
            throw new PayCoreBizException(PayCoreErrorCode.FREEZE_ORDER_NO_EXIST);
        } else if (!PayStatusEnums.SUCCESS.getCode().equals(freezeBO.getStatus())) {
            log.error("对应的冻结订单未成功,冻结单号:{}", withdrawDTO.getOrigPayNo());
            throw new PayCoreBizException(PayCoreErrorCode.FREEZE_ORDER_NO_SUC);
        }
        List<WithdrawFundBO> withdrawFundBOs = new ArrayList<>();
        if (Constant.validateLong(withDrawFundDTO.getBizChargeAmount()) > 0) {
            //获取转账手续费会计事件
            String eventNo = getEventNo(withdrawDTO);
            //解冻转账单
            WithdrawFundBO withdrawFundByTransfer = this.assembleWithdrawFund(withdrawBO.getPayNo(), withdrawBO.getAccountNo(), withdrawDTO,
                    withDrawFundDTO, FundTypeEnum.FEE, withDrawFundDTO.getBizChargeAmount(), 1, freezeBO);
            withdrawFundByTransfer.setEventNo(eventNo);
            withdrawFundBOs.add(withdrawFundByTransfer);
        }
        //解冻提现单
        Long unfreezeAmt = withDrawFundDTO.getAmt() - Constant.validateLong(withDrawFundDTO.getBizChargeAmount());
        WithdrawFundBO withdrawFundByUnfreeze = this.assembleWithdrawFund(withdrawBO.getPayNo(), withdrawBO.getAccountNo(), withdrawDTO,
                withDrawFundDTO, FundTypeEnum.UNFREEZE_WITHDRAW, unfreezeAmt, 2, freezeBO);
        withdrawFundBOs.add(withdrawFundByUnfreeze);

        withdrawBO.setWithdrawFundBO(withdrawFundBOs);
    }

    /**
     * 组装资金渠道
     *
     * @param payNo             支付单号
     * @param withdrawDTO       提现请求参数
     * @param withDrawFundDTO   提现资金单
     * @param fundTypeEnum      资金类型
     * @param reqAccAmt         请求账务金额
     * @return                  资金单
     */
    private WithdrawFundBO assembleWithdrawFund(String payNo, String accountNo, UnfreezeWithdrawDTO withdrawDTO, WithDrawFundDTO withDrawFundDTO,
                                                FundTypeEnum fundTypeEnum, Long reqAccAmt, int sort,FreezeBO freezeBO) {

        WithdrawFundBO withdrawFundBO = new WithdrawFundBO();

        withdrawFundBO.setPayNo(payNo);
        //资金明细No
        withdrawFundBO.setFundDetailNo(sequenceFacade.getUniqueSeq());
        withdrawFundBO.setStatus(PayStatusEnums.INIT.getCode());
        withdrawFundBO.setAccountNo(accountNo);
        withdrawFundBO.setPayToolType(PayToolTypeEnum.ACCOUNT.getCode());
        withdrawFundBO.setAmt(withDrawFundDTO.getAmt());
        withdrawFundBO.setCcy(withDrawFundDTO.getCcy());
        withdrawFundBO.setAgreeRelId(withDrawFundDTO.getAgreeRelId());
        withdrawFundBO.setAgreementNo(withDrawFundDTO.getAgreementNo());
        withdrawFundBO.setBizFeeAccount(accountNo);
        withdrawFundBO.setFundType(fundTypeEnum.getCode());
        withdrawFundBO.setReqAccAmt(reqAccAmt);
        withdrawFundBO.setSort(sort);
        if(ServiceCodeEnum.UNFRE_WITHDRAW.getCode().equals(withdrawDTO.getServiceCode())){
            withdrawFundBO.setEventNo(getUnfreezeEventNo(withdrawDTO));
        }
        if(freezeBO.getFreezeCode()==null){
            throw new PayCoreBizException(PayCoreErrorCode.FREEZE_ORDER_NO_FREEZECODE);
        }
        withdrawFundBO.setFreezeCode(freezeBO.getFreezeCode());
        //解冻单号
        withdrawFundBO.setUnfreezeNo(sequenceFacade.getUniqueSeq());

        return withdrawFundBO;
    }

    /**
     * 获取会计事件号
     *
     * @param withdrawDTO   提现请求参数
     * @return              会计事件号
     */
    private String getEventNo(UnfreezeWithdrawDTO withdrawDTO){
        EventRuleResBO eventRuleResBO = eventService.queryEventNo(EventTypeEnum.FEE, withdrawDTO.getSubBizType());
        if (!PayStatusEnums.SUCCESS.getCode().equals(eventRuleResBO.getStatus())) {
            log.error("会计事件获取失败:{}",withdrawDTO.getBizType());
            throw new BizServiceException(PayCoreErrorCode.EVENT_NO_NOT_EXIST, eventRuleResBO.getErrorMsg());
        }
        return eventRuleResBO.getEventNo();
    }

    /**
     * 获取会计事件号
     *
     * @param withdrawDTO   提现请求参数
     * @return              会计事件号
     */
    private String getUnfreezeEventNo(UnfreezeWithdrawDTO withdrawDTO){
        EventRuleResBO eventRuleResBO = eventService.queryByEventInfo(EventTypeEnum.PRODUCT_CHANNEL, withdrawDTO.getSubBizType(),withdrawDTO.getProductChannel());
        if (!PayStatusEnums.SUCCESS.getCode().equals(eventRuleResBO.getStatus())) {
            log.error("会计事件获取失败:{}",withdrawDTO.getBizType());
            throw new BizServiceException(PayCoreErrorCode.EVENT_NO_NOT_EXIST, eventRuleResBO.getErrorMsg());
        }
        return eventRuleResBO.getEventNo();
    }
}
